"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" fjrti vim config
" fjrti@163.com
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
" basic configuration
"
if &compatible | set nocompatible | endif
set nocursorline
if exists('$TMUX') | set term=screen-256color | endif
set history=1000
filetype plugin on
filetype indent on
set nofixeol
set autoread
set scrolloff=7
let $LANG='en'
set langmenu=en
set wildchar=<Tab>
set wildmenu
set wildmode=full
set wildoptions+=pum
set wildoptions+=fuzzy
set wildignore+=*.o,*~,*.pyc,*/.git/*,*/.hg/*,*/.svn/*,*/.DS_Store
set wildignore+=*swp,*.class,*.png,*.jpg,*.gif,*.zip
" set ruler
set hidden
set ttyfast
set ttymouse=xterm2
set viminfo+=!
set display=lastline
set backspace=eol,start,indent
set whichwrap+=h,l,~,[,],<,>
set ignorecase
set smartcase
set hlsearch
set incsearch
" set lazyredraw
set magic
set showmatch
set mat=1
set noerrorbells
set novisualbell
set splitright
set splitbelow
set autowrite
set mousehide
set linespace=0
set t_vb=
set t_ut=
syntax sync minlines=300
set fileformats=unix,dos,mac
set nobackup
set nowritebackup
set noswapfile
set nowb
set expandtab
set smarttab
set shiftwidth=4
set tabstop=4
set linebreak
set textwidth=500
set autoindent
set nowrap
set path=.,**
set noeb
" TODO
" set timeoutlen=500
set timeoutlen=5000
set ttimeoutlen=200
set ttimeout
set nostartofline
set noshowmode
set updatetime=200
if !exists('$vim_simple') | set laststatus=2 | endif
set pumheight=20
set winminheight=0
set cpt=.,k,w,b
" set completeopt=menu,menuone,noselect
set completeopt=menu,menuone
set shortmess+=c
" set shortmess=filnxtToO
set tags+=./.tags;,.tags;tags;

let $LANG='en' 
set langmenu=en
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,sjis,euc-kr,ucs-2le,latin1
set encoding=utf-8
" set encoding=chinese
set termencoding=chinese
set fileencoding=chinese
if v:lang =~ "utf8$" || v:lang =~ "UTF-8$"
    set encoding=utf-8
    set termencoding=utf-8
    set fileencoding=utf-8
endif
set confirm

if exists('$vim_simple')
    " set fillchars=vert:\ 
    " set fillchars=vert:│
else
    set fillchars=vert:│
endif

set listchars=tab:\|\ ,trail:.,extends:>,precedes:<
exe "set sbr=\u21b3"

set foldmethod=manual

"
" key map
"
map <c-s> <nop>
command W w !sudo tee % > /dev/null
noremap <c-b> <left>
noremap <c-j> <down>
noremap <c-k> <up>
noremap <c-l> <right>
noremap <c-f> <right>
inoremap <c-b> <left>
" inoremap <c-j> <down>
" inoremap <c-k> <up>
inoremap <c-l> <right>
inoremap <c-a> <home>
inoremap <c-e> <end>
inoremap <c-d> <del>
inoremap <c-_> <c-k>
cnoremap <c-b> <left>
cnoremap <c-j> <down>
cnoremap <c-k> <up>
cnoremap <c-f> <right>
cnoremap <c-a> <home>
inoremap <c-a> <c-o>0
cnoremap <c-e> <end>
inoremap <c-e> <c-o>$
cnoremap <c-b> <left>
cnoremap <c-d> <del>
cnoremap <c-_> <c-k>
inoremap <c-u> <c-g>u<c-u>

" window management
noremap <silent><s-tab> :tabnext<cr>
inoremap <silent><s-tab> <ESC>:tabnext<cr>
nnoremap <bs> :b#<cr>
" set switchbuf=useopen,usetab,newtab
" set showtabline=2
nnoremap H ^
nnoremap L $
vnoremap v <Esc>
" replace with vim-arpeggio
" inoremap jj <esc>
" inoremap jk <esc>
" lmap     jk <esc>
" inoremap j<space> j
" nnoremap ; :
nnoremap j gj
nnoremap k gk
vnoremap j gj
vnoremap k gk
nnoremap U <c-r>
nnoremap Y y$
autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
autocmd BufReadPost quickfix nnoremap <buffer> <CR> <CR>
noremap f /
vnoremap f /
nnoremap F ?
vnoremap F ?
vnoremap < <gv
vnoremap > >gv
"select last pasted content
nnoremap gp `[v`]

nnoremap ma mA
nnoremap mb mB
nnoremap mc mC
nnoremap mm mM
nnoremap 'a 'A
nnoremap 'b 'B
nnoremap 'c 'C
nnoremap 'm 'M
nnoremap '' 'M

"
" custom command
"
command! ZEnterCurrentDirectory call s:enter_current_directory()
command! ZRoot call s:enter_root_directory()
command! ZCleanTailspace call s:clean_tail_spaces()
command! ZDeleteDupBankLine call s:clean_dup_bank_line()
command! ZDosToUnix call s:dos_to_unix()
command! ZFindCursor call s:find_cursor()
command! ZReplace call s:local_file_replace(expand('<cword>'), 1)
command! ZDiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis | wincmd p | diffthis
command! ZDiffToggleWhiteSpace call s:toggle_diff_whitespace()
command! -nargs=? Filter let @a='' | execute 'g/<args>/y A' | new | setlocal bt=nofile | put! a
command! ZPath echo expand("%:p")
command! -bang ZForbiddenExit call s:forbidden_vim_exit(<bang>0)
command! -nargs=0 -bar ZUpdate if &modified | if empty(bufname('%')) | browse confirm write | else | confirm write | endif |endif
command! -nargs=+ -complete=command ZMessage call s:tab_message(<q-args>)

" call delete(expand('%')) | bdelete!
command! ZRemoveCurrentFile call delete(expand('%')) | bdelete!
" command! -range Translate call s:translate(<line1>, <line2>) 
command! -bang -nargs=* -complete=file Make AsyncRun -save=2 -program=make @ <args>

"
" function
"

func! s:translate(line1, line2)
    let save_cursor = getpos(".")
    let lines = getline(a:line1, a:line2)
	if &encoding != 'utf-8'
		let lines = map(lines, 'iconv(v:val, &encoding, "utf-8")')
	endif
    let content = join(lines, " ")
    exec printf("%dr !trans '%s'", a:line2, content)
	call setpos('.', save_cursor)
	if a:line1 == a:line2 
		exec 'normal! dd'
	endif
endfunc

function! TranslateCurrentLine()
    " Get the current line content
    let l:current_line = getline('.')

    " Check if the current line is empty
    if empty(l:current_line)
        echom "Error: Current line is empty"
        return
    endif

    " Use shellescape () to correctly escape input
    let l:cmd = 'trans ' . shellescape(l:current_line)

    " Invoke the trans command and get the output
    try
        let l:translated = system(l:cmd)
        " Check if the command was successfully executed
        if v:shell_error != 0
            echom "Error: trans command failed with error code " . v:shell_error
            return
        endif

        " Remove newline characters from output
        let l:translated = substitute(l:translated, '\n\+$', '', '')

        " Replace the current line content
        call setline('.', l:translated)
    catch
        echom "Error: Failed to execute trans command: " . v:exception
    endtry
endfunction

function! TranslateText() range
	" Get the selected line (a: firstline and a:lastline in visual mode）
    let l:lines = getline(a:firstline, a:lastline)

    " Check if it is empty
    if empty(l:lines)
        echom "Error: No text selected"
        return
    endif

    " Merge multiple lines, separated by spaces
    let l:input_text = join(l:lines, ' ')

    " Use shellescape () to escape input
    let l:cmd = 'trans ' . shellescape(l:input_text)

    try
        let l:translated = system(l:cmd)
        " Check if the command was successfully executed
        if v:shell_error != 0
            echom "Error: trans command failed with error code " . v:shell_error
            return
        endif

        " Remove newline characters from output
        let l:translated = substitute(l:translated, '\n\+$', '', '')

        " Replace the selected line
        " Delete original selected row
        execute a:firstline . ',' . a:lastline . 'delete _'
        " Insert translation result
        call append(a:firstline - 1, l:translated)
    catch
        echom "Error: Failed to execute trans command: " . v:exception
    endtry
endfunction

command! Translate call TranslateText()<CR>

func! s:toggle_diff_whitespace()
  if stridx(&diffopt, "iwhite") >= 0
    set diffopt-=iwhite
    echo "Not ignoring whitespaces in diff"
  else
    set diffopt+=iwhite
    echo "Whitespaces ignored in diff"
  endif
  windo diffupdate
endfunc

function! s:clean_tail_spaces()
    let save_cursor = getpos(".")
    let old_query = getreg('/')
    silent! %s/\s\+$//e
    call setpos('.', save_cursor)
    call setreg('/', old_query)
endfun

function! s:clean_dup_bank_line()
    let save_cursor = getpos(".")
    let old_query = getreg('/')
    silent! %s/\s\+$//e
    silent! g/^\(\s*\)$\n\1$/d
    call setpos('.', save_cursor)
    call setreg('/', old_query)
endfun

function! s:dos_to_unix()
    let save_cursor = getpos(".")
    let old_query = getreg('/')
    silent! %s/\r//g
    call setpos('.', save_cursor)
    call setreg('/', old_query)
endfun

function! s:tab_message(cmd)

    redir => message
    silent execute a:cmd
    redir END

    if empty(message)
        echoerr "no output"
    else
        " use "new" instead of "tabnew" below if you prefer split windows instead of tabs
        tabnew
        setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted nomodified
        silent put=message
    endif
endfunction

function! s:forbidden_vim_exit(flag)
    if a:flag == 0
        cabbrev q <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'close' : 'q')<CR>
        cabbrev x <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'echo "Lock quit"' : 'x')<CR>
        cabbrev quit <c-r>=(getcmdtype()==':' ? 'echo "Lock quit"' : 'quit')<CR>
        cabbrev exit <c-r>=(getcmdtype()==':' ? 'echo "Lock quit"' : 'exit')<CR>
        cabbrev wq <c-r>=(getcmdtype()==':' ? 'echo "Lock quit"' : 'wq')<CR>
        cabbrev wqa <c-r>=(getcmdtype()==':' ? 'echo "Lock quit"' : 'wqa')<CR>
        cabbrev qa <c-r>=(getcmdtype()==':' ? 'echo "Lock quit"' : 'qa')<CR>
        map ZZ <nop>

        " if executable('tmux') && strlen($TMUX)
        "     silent !tmux set status off
        "     silent !tmux list-panes -F '\#F' | grep -q Z || tmux resize-pane -Z
        " endif

    else

        " if executable('tmux') && strlen($TMUX)
        "     silent !tmux set status on
        "     silent !tmux list-panes -F '\#F' | grep -q Z && tmux resize-pane -Z
        " endif

        " TODO: has error
        exec 'cunabbrev q'
        exec 'cunabbrev x'
        exec 'cunabbrev quit'
        exec 'cunabbrev exit'
        exec 'cunabbrev wq'
        exec 'cunabbrev wqa'
        exec 'cunabbrev qa'
        exec 'unmap ZZ'
    endif
endfun

function! s:enter_current_directory()
    silent! cd %:p:h
    pwd
endfun

function! s:enter_root_directory()
    exec 'cd' fnameescape(fnamemodify(finddir('.git', escape(expand('%:p:h'), ' ') . ';'), ':h'))
    pwd
endfun

" TODO: restore cursorline
function! s:find_cursor()
    set cursorline cursorcolumn
    redraw
    sleep 500m
    " TODO
    set nocursorline nocursorcolumn
endfunction

function! s:echo_warning(msg)
  echohl WarningMsg
  echo "Warning"
  echohl None
  echon ': ' a:msg
endfunction

" local file replace, alike with easygrep
function! s:local_file_replace(str, wholeword)
    echon "Replace [" | echohl WarningMsg | echon a:str | echohl None | echon "] in current file with: "
    let r = input("", a:str)
    if empty(r)
        let confirmed = confirm("Proceed replacing '".a:str."' with an empty pattern, effectively deleting it?", "&Yes\n&No")-1
        if confirmed
            return
        endif
    endif
    if r ==# a:str
        echo " "
        echo "No change in pattern, ignoring"
        return
    endif

    " start replace
    let save_cursor = getpos(".")
    exec '%s/\<'.a:str.'\>/'.r.'/g'
    call setpos('.', save_cursor)
endfunction

" :e this/does/not/exist/file.txt
" :w
function s:Mkdir()
  let dir = expand('%:p:h')
  if dir =~ '://'
    return
  endif
  if !isdirectory(dir)
    call mkdir(dir, 'p')
    echo 'Created non-existing directory: '.dir
  endif
endfunction
autocmd BufWritePre * call s:Mkdir()

" for jumplist
function! GotoJump()
  jumps
  let j = input("Please select your jump: ")
  if j != ''
    let pattern = '\v\c^\+'
    if j =~ pattern
      let j = substitute(j, pattern, '', 'g')
      execute "normal " . j . "\<c-i>"
    else
      execute "normal " . j . "\<c-o>"
    endif
  endif
endfunction

" jumplist, leader jump
nnoremap <space>gj :call GotoJump()<CR>

" Automatically set paste mode 
" https://coderwall.com/p/if9mda/automatically-set-paste-mode-in-vim-when-pasting-in-insert-mode
function! WrapForTmux(s)
  if !exists('$TMUX')
    return a:s
  endif

  let tmux_start = "\<Esc>Ptmux;"
  let tmux_end = "\<Esc>\\"

  return tmux_start . substitute(a:s, "\<Esc>", "\<Esc>\<Esc>", 'g') . tmux_end
endfunction

function! XTermPasteBegin()
  set pastetoggle=<Esc>[201~
  set paste
  return ""
endfunction

" for prg test
autocmd BufNewFile sol.cpp 0r ~/cpp_template.cpp
autocmd BufNewFile,BufRead sol.c setlocal makeprg=gcc\ %\ -o\ %<\ -Wall\ -std=gnu11\ -static\ -lm\ -O2\ -DLOCAL
autocmd BufNewFile,BufRead sol.cpp setlocal makeprg=g++\ %\ -o\ %<\ -Wall\ -std=c++14\ -O2\ -DLOCAL

" start 10m timer
let g:confirm_quit = 0
autocmd VimEnter * call timer_start(600000, {-> execute('let g:confirm_quit = 1')})

function Set()
    if winnr('$')>1
        wincmd l
        wincmd k
        write
        wincmd t
        only
    endif
    write
endfunc

function Run()
    call Set()
    !(%< <%<.in >%<.out)2>>%<.out
    belowright vsplit %<.in
    belowright sview %<.out
    wincmd t
    redraw!
endfunc

function Run_with_time()
    call Set()
    !(time %< <%<.in >%<.out)2>>%<.out
    belowright vsplit %<.in
    belowright sview %<.out
    wincmd t
    redraw!
endfunc

function AutoRun()
    call Set()
    let v:statusmsg=''
    make
    if empty(v:statusmsg)
        call Run()
    else
        cwindow
        winc t
        redraw!
    endif
endfunc

function! CompressEmptyLines()
  let save_pos = getpos('.')
  let current_line = line('.')

  try
    if getline(current_line) !~ '^\s*$'
      call setpos('.', save_pos)
      return
    endif

    let start_line = current_line
    while start_line > 1 && getline(start_line - 1) =~ '^\s*$'
      let start_line -= 1
    endwhile

    let end_line = current_line
    let max_line = line('$')
    while end_line < max_line && getline(end_line + 1) =~ '^\s*$'
      let end_line += 1
    endwhile

    silent! execute start_line . ',' . end_line . 's/\n\s*\n\+/\r/'
    call setpos('.', [0, start_line, 1, 0])
  finally
    nohlsearch
    redraw
  endtry
endfunction

nnoremap <silent> zdd :call CompressEmptyLines()<CR>

